﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DynaPrecision.LinearSystem
{
	[Serializable]
	public class Vector<T> : IVector<T>, IEquatable<Vector<T>>
	{
		public void SetStorage(List<T> storage)
		{
			this._storage = storage;
		}
		public void ResizeStorage(int newCount)
		{
			if (this.Count == newCount) return;
			else if (this.Count < newCount)
			{
				while (this.Count < newCount)
				{
					this._storage.Add(DefaultValueProvider<T>.GetZero());
				}
				return;
			}
			else
			{
				while (this.Count > newCount)
				{
					this._storage.RemoveAt(this.Count - 1);
				}
			}
		}
		public IList<T> AsList()
		{
			return this._storage;
		}
		private List<T> _storage = new List<T>();

		public Vector() { ;}
		public Vector(IEnumerable<T> data)
		{
			this._storage.AddRange(data);
		}
		public Vector(params T[] data)
		{
			this._storage.AddRange(data);
		}


		public override string ToString()
		{
			StringBuilder sb = new StringBuilder();
			foreach (var aT in _storage)
			{
				sb.Append(aT.ToString());
				sb.Append("\t ");
			}
			return sb.ToString();
		}
		#region IVector<T> Members

		public T this[int index]
		{
			get
			{
				return this._storage[index];
			}
			set
			{
				this._storage[index] = value;
			}
		}

		public int Count
		{
			get { return this._storage.Count; }
		}

		public T Norm
		{
			get
			{
				return DefaultValueProvider<T>.GetValueFromDouble(
					Math.Sqrt(
					this._storage.Select(_t => ((double)(dynamic)_t) * ((double)(dynamic)_t)).Sum()));
			}
		}
		public static IEnumerable<T> ZeroOrData(IList<T> from, int totalCount)
		{
			int k = 0;
			while (k < from.Count && k < totalCount)
			{
				yield return from[k];
				k++;
			}
			while (k < totalCount)
			{
				yield return DefaultValueProvider<T>.Zero;
				k++;
			}
		}
		#endregion
		public static Vector<T> operator +(Vector<T> l, Vector<T> r)
		{
			if (l.Count == r.Count)
			{
				return new Vector<T>(l._storage.Select((_c, _index) => (T)(_c + (dynamic)r[_index])));
			}
			else 
			{
				int total = l.Count > r.Count ? l.Count : r.Count;
				var __l = ZeroOrData(l._storage, total);
				var __r = ZeroOrData(r._storage, total).ToList();
				return new Vector<T>(__l.Select((_c,_index)=>(T)(_c+(dynamic)__r[_index])));
			}
		}
		public static Vector<T> operator -(Vector<T> l, Vector<T> r)
		{
			if (l.Count == r.Count)
			{
				return new Vector<T>(l._storage.Select((_c, _index) => (T)(_c - (dynamic)r[_index])));
			}
			else
			{
				int total = l.Count > r.Count ? l.Count : r.Count;
				var __l = ZeroOrData(l._storage, total);
				var __r = ZeroOrData(r._storage, total).ToList();
				return new Vector<T>(__l.Select((_c, _index) => (T)(_c - (dynamic)__r[_index])));
			}
		}
		public static Vector<T> operator *(Vector<T> l, T r)
		{
			return new Vector<T>(l._storage.Select(_c => (T)(_c * (dynamic)r)));
		}
		public static Vector<T> operator *(T r, Vector<T> l)
		{
			return new Vector<T>(l._storage.Select(_c => (T)(_c * (dynamic)r)));
		}
		public static Vector<T> operator /(Vector<T> l, T r)
		{
			return new Vector<T>(l._storage.Select(_c => (T)(_c / (dynamic)r)));
		}
		public static bool operator ==(Vector<T> l, Vector<T> r)
		{
			if (l == null || r == null) return false;
			bool result = true;
			if (l.Count != r.Count) return false;
			for (int i = 0; i < l.Count && i < r.Count; i++)
			{
				result = result && (l[i].Equals(r[i]));
			}
			return result;
		}
		public static bool operator !=(Vector<T> l, Vector<T> r)
		{
			return !(l == r);
		}
		public override bool Equals(object obj)
		{
			if (obj == null) return false;
			if (obj is Vector<T>)
			{
				return (this as IEquatable<Vector<T>>).Equals(obj as Vector<T>);
			}
			else return false;
		}
		public override int GetHashCode()
		{
			return base.GetHashCode();
		}
		public static explicit operator Vector<T>(List<T> list)
		{
			Vector<T> result = new Vector<T>();
			result._storage = list;
			return result;
		}
		public static explicit operator Vector<T>(double from)
		{
			Vector<T> result = new Vector<T>((T)(dynamic)from);
			return result;
		}

		#region IEquatable<Vector<T>> Members

		public bool Equals(Vector<T> other)
		{
			if (other == null) return false;
			if (this.Count != other.Count) return false;
			bool result = true;
			for (int i = 0; i < this.Count && i < other.Count; i++)
			{
				result = (result && this[i].Equals(other[i]));
			}
			return result;
		}

		#endregion
	}
}